package com.sanri.tools.modules.redis.service.dtos;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sanri.tools.modules.core.dtos.param.ConnectParam;
import com.sanri.tools.modules.core.dtos.param.RedisConnectParam;
import com.sanri.tools.modules.redis.service.ColonCommandReply;
import com.sanri.tools.modules.redis.service.CommandReply;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.validation.annotation.Validated;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 单台哨兵节点
 */
@Data
@Slf4j
public class SentinelNode {
    private String id;
    private HostAndPort hostAndPort;
    private String role;
    /**
     * 父级 id
     */
    private String masterId;

    /**
     * 兄弟节点列表
     */
    private List<SentinelNode> siblingNodes = new ArrayList<>();

    /**
     * info 信息, 避免重复翻译
     */
    private RedisNode.Info info = new RedisNode.Info();

    /**
     * 返回当前节点是否为哨兵
     * @param hostAndPort
     * @param redisConnectParam
     * @return true: 刷新成功, 当前节点为哨兵, false: 不是哨兵
     */
    public boolean refresh(HostAndPort hostAndPort, RedisConnectParam redisConnectParam){
        return refreshSelf(hostAndPort,redisConnectParam);
//        refreshSiblings();
    }

    public boolean refreshSelf(HostAndPort hostAndPort, RedisConnectParam redisConnectParam){
        Jedis jedis = new Jedis(hostAndPort.getHost(),hostAndPort.getPort());
        String sentinelPassword = redisConnectParam.getSentinelPassword();
        if (StringUtils.isNotBlank(sentinelPassword)){
            jedis.auth(sentinelPassword);
        }

        try{
            // 判断模式是否为哨兵
            final RedisNode.Server server = RedisNode.server(jedis);
            info.setServer(server);

            id = hostAndPort.toString();
            this.hostAndPort = hostAndPort;

            if (!"sentinel".equals(server.getMode())){
                return false;
            }

            // 当前节点是哨兵, 解析哨兵信息
            final Sentinel sentinel = SentinelNode.sentinelInfo(jedis);
            info.setSentinel(sentinel);
        }finally {
            jedis.close();
        }
        return true;
    }

    /**
     * 获取哨兵信息
     * @return
     */
    public static final Sentinel sentinelInfo(Jedis jedis){
        String info = jedis.info("Sentinel");
        final Sentinel sentinel = new Sentinel();
        List<String[]> parser = CommandReply.colonCommandReply.parser(info);
        for (String[] line : parser) {
            if (line.length == 2){

            }else if (line.length == 3 && line[0].startsWith("master")){
                // 重新解析当前行
                line[0] = line[0] + ":" + line[1] + ":"+ line[2];

                Sentinel.Master master = new Sentinel.Master();
                sentinel.getMasterList().add(master);

                line = StringUtils.splitPreserveAllTokens(line[0], ',');
                for (String splitInfo : line) {
                    final String[] items = StringUtils.splitPreserveAllTokens(splitInfo, '=');
                    if (items.length == 2) {
                        String key = items[0];
                        if (key.startsWith("master")){
                            int index = NumberUtils.toInt(key.substring(6,7));
                            master.setIndex(index);
                            master.setName(items[1]);
                        }else {
                            switch (key){
                                case "status":
                                    master.setStatus(items[1]);
                                    break;
                                case "address":
                                    final HostAndPort hostAndPort = HostAndPort.parseString(items[1]);
                                    master.setHostAndPort(hostAndPort);
                                    break;
                                case "slaves":
                                    master.setSlaves(NumberUtils.toInt(items[1]));
                                    break;
                                case "sentinels":
                                    master.setSentinels(NumberUtils.toInt(items[1]));
                                    break;
                                default:
                                    log.info("转换哨兵属性时,未知属性:{}",key);
                            }
                        }
                    }
                }

            }
        }
        return sentinel;
    }

    @Data
    public static final class Sentinel{
        private int masters;
        private int tilt;
        private int runingScripts;
        private int scriptsQueueLength;
        private List<Master> masterList = new ArrayList<>();

        @Data
        public static final class Master{
            private int index;
            private String name;
            private String status;
            private HostAndPort hostAndPort;
            private int slaves;
            private int sentinels;
        }
    }

}
